package com.example.allshengmedical.util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;

/**
 * 
 * 
 * @author WillJoe
 * 
 */
@SuppressLint("NewApi")
public class DragGridView extends GridView {
	/**
	 * DragGridView的item长按响应的时间， 默认是1000毫秒，也可以自行设置
	 */
	private long dragResponseMS = 500;

	/**
	 * 是否可以拖拽，默认可以
	 */
	public boolean isDrag = true;

	private int mDownX;
	private int mDownY;
	private int moveX;
	private int moveY;
	/**
	 * 正在拖拽的position
	 */
	private int mDragPosition;

	/**
	 * 刚开始拖拽的item对应的View
	 */
	private View mStartDragItemView = null;

	/**
	 * 用于拖拽的镜像，这里直接用一个ImageView
	 */
	private ImageView mDragImageView;

	/**
	 * 震动器
	 */
	private Vibrator mVibrator;

	private WindowManager mWindowManager;
	/**
	 * item镜像的布局参数
	 */
	private WindowManager.LayoutParams mWindowLayoutParams;

	/**
	 * 我们拖拽的item对应的Bitmap
	 */
	private Bitmap mDragBitmap;

	/**
	 * 按下的点到所在item的上边缘的距离
	 */
	private int mPoint2ItemTop;

	/**
	 * 按下的点到所在item的左边缘的距离
	 */
	private int mPoint2ItemLeft;

	/**
	 * DragGridView距离屏幕顶部的偏移量
	 */
	private int mOffset2Top;

	/**
	 * DragGridView距离屏幕左边的偏移量
	 */
	private int mOffset2Left;

	/**
	 * 状态栏的高度
	 */
	private int mStatusHeight;

	/**
	 * DragGridView自动向下滚动的边界值
	 */
	private int mDownScrollBorder;

	/**
	 * DragGridView自动向上滚动的边界值
	 */
	private int mUpScrollBorder;

	/**
	 * DragGridView自动滚动的速度
	 */
	private static final int speed = 80;

	/**
	 * item发生变化回调的接口
	 */
	private OnChanageListener onChanageListener;

	public DragGridView(Context context) {
		this(context, null);
	}

	public DragGridView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public DragGridView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mVibrator = (Vibrator) context
				.getSystemService(Context.VIBRATOR_SERVICE);
		mWindowManager = (WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE);
		mStatusHeight = getStatusHeight(context); // 获取状态栏的高度
	}

	private Handler mHandler = new Handler();

	// 用来处理是否为长按的Runnable
	private Runnable mLongClickRunnable = new Runnable() {

		@Override
		public void run() {

			mVibrator.vibrate(50); // 震动一下
			mStartDragItemView.setVisibility(View.INVISIBLE);// 隐藏该item

			// 根据我们按下的点显示item镜像
			createDragImage(mDragBitmap, mDownX, mDownY);
		}
	};

	/**
	 * 设置回调接口
	 * 
	 * @param onChanageListener
	 */
	public void setOnChangeListener(OnChanageListener onChanageListener) {
		this.onChanageListener = onChanageListener;
	}

	/**
	 * 设置响应拖拽的毫秒数，默认是1000毫秒
	 * 
	 * @param dragResponseMS
	 */
	public void setDragResponseMS(long dragResponseMS) {
		this.dragResponseMS = dragResponseMS;
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:

			if (isDrag) {
				// 使用Handler延迟dragResponseMS执行mLongClickRunnable
				mHandler.postDelayed(mLongClickRunnable, dragResponseMS);

				mDownX = (int) ev.getX();
				mDownY = (int) ev.getY();

				// 根据按下的X,Y坐标获取所点击item的position
				mDragPosition = pointToPosition(mDownX, mDownY);

				if (mDragPosition == AdapterView.INVALID_POSITION) {
					return super.dispatchTouchEvent(ev);
				}

				// 根据position获取该item所对应的View
				mStartDragItemView = getChildAt(mDragPosition
						- getFirstVisiblePosition());

				// 下面这几个距离大家可以参考我的博客上面的图来理解下
				mPoint2ItemTop = mDownY - mStartDragItemView.getTop();
				mPoint2ItemLeft = mDownX - mStartDragItemView.getLeft();

				mOffset2Top = (int) (ev.getRawY() - mDownY);
				mOffset2Left = (int) (ev.getRawX() - mDownX);

				// 获取DragGridView自动向上滚动的偏移量，小于这个值，DragGridView向下滚动
				mDownScrollBorder = getHeight() / 4;
				// 获取DragGridView自动向下滚动的偏移量，大于这个值，DragGridView向上滚动
				mUpScrollBorder = getHeight() * 3 / 4;

				// 开启mDragItemView绘图缓存
				mStartDragItemView.setDrawingCacheEnabled(true);
				// 获取mDragItemView在缓存中的Bitmap对象
				mDragBitmap = Bitmap.createBitmap(mStartDragItemView
						.getDrawingCache());
				// 这一步很关键，释放绘图缓存，避免出现重复的镜像
				mStartDragItemView.destroyDrawingCache();
			}

			break;
		case MotionEvent.ACTION_MOVE:

			if (isDrag) {
				int moveX = (int) ev.getX();
				int moveY = (int) ev.getY();

				// 如果我们在按下的item上面移动，只要不超过item的边界我们就不移除mRunnable
				if (!isTouchInItem(mStartDragItemView, moveX, moveY)) {
					mHandler.removeCallbacks(mLongClickRunnable);
				}
			}

			break;
		case MotionEvent.ACTION_UP:

			if (isDrag) {
				mHandler.removeCallbacks(mLongClickRunnable);
				mHandler.removeCallbacks(mScrollRunnable);
			}

			break;
		}
		return super.dispatchTouchEvent(ev);
	}

	/**
	 * 是否点击在GridView的item上面
	 * 
	 * @param itemView
	 * @param x
	 * @param y
	 * @return
	 */
	private boolean isTouchInItem(View dragView, int x, int y) {
		if (isDrag) {
			int leftOffset = dragView.getLeft();
			int topOffset = dragView.getTop();
			if (x < leftOffset || x > leftOffset + dragView.getWidth()) {
				return false;
			}

			if (y < topOffset || y > topOffset + dragView.getHeight()) {
				return false;
			}
		}

		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (isDrag && mDragImageView != null) {
			switch (ev.getAction()) {
			case MotionEvent.ACTION_MOVE:
				moveX = (int) ev.getX();
				moveY = (int) ev.getY();
				// 拖动item
				onDragItem(moveX, moveY);
				break;
			case MotionEvent.ACTION_UP:
				if (isDrag) {
					onStopDrag();
				}

				break;
			}
			return true;
		}
		return super.onTouchEvent(ev);
	}

	/**
	 * 创建拖动的镜像
	 * 
	 * @param bitmap
	 * @param downX
	 *            按下的点相对父控件的X坐标
	 * @param downY
	 *            按下的点相对父控件的X坐标
	 */
	private void createDragImage(Bitmap bitmap, int downX, int downY) {
		if (isDrag) {
			mWindowLayoutParams = new WindowManager.LayoutParams();
			mWindowLayoutParams.format = PixelFormat.TRANSLUCENT; // 图片之外的其他地方透明
			mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
			mWindowLayoutParams.x = downX - mPoint2ItemLeft + mOffset2Left;
			mWindowLayoutParams.y = downY - mPoint2ItemTop + mOffset2Top
					- mStatusHeight;
			mWindowLayoutParams.alpha = 0.55f; // 透明度
			mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
			mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
			mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
					| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

			mDragImageView = new ImageView(getContext());
			mDragImageView.setImageBitmap(bitmap);
			mWindowManager.addView(mDragImageView, mWindowLayoutParams);
		}

	}

	/**
	 * 从界面上面移动拖动镜像
	 */
	private void removeDragImage() {
		if (isDrag) {
			if (mDragImageView != null) {
				mWindowManager.removeView(mDragImageView);
				mDragImageView = null;
			}
		}

	}

	/**
	 * 拖动item，在里面实现了item镜像的位置更新，item的相互交换以及GridView的自行滚动
	 * 
	 * @param x
	 * @param y
	 */
	private void onDragItem(int moveX, int moveY) {
		mWindowLayoutParams.x = moveX - mPoint2ItemLeft + mOffset2Left;
		mWindowLayoutParams.y = moveY - mPoint2ItemTop + mOffset2Top
				- mStatusHeight;
		mWindowManager.updateViewLayout(mDragImageView, mWindowLayoutParams); // 更新镜像的位置
		onSwapItem(moveX, moveY);

		// GridView自动滚动
		mHandler.post(mScrollRunnable);
	}

	/**
	 * 当moveY的值大于向上滚动的边界值，触发GridView自动向上滚动 当moveY的值小于向下滚动的边界值，触犯GridView自动向下滚动
	 * 否则不进行滚动
	 */
	private Runnable mScrollRunnable = new Runnable() {

		@Override
		public void run() {
			int scrollY;
			if (moveY > mUpScrollBorder) {
				scrollY = -speed;
				mHandler.postDelayed(mScrollRunnable, 25);
			} else if (moveY < mDownScrollBorder) {
				scrollY = speed;
				mHandler.postDelayed(mScrollRunnable, 25);
			} else {
				scrollY = 0;
				mHandler.removeCallbacks(mScrollRunnable);
			}

			// 当我们的手指到达GridView向上或者向下滚动的偏移量的时候，可能我们手指没有移动，但是DragGridView在自动的滚动
			// 所以我们在这里调用下onSwapItem()方法来交换item
			onSwapItem(moveX, moveY);

			View view = getChildAt(mDragPosition - getFirstVisiblePosition());
			// 实现GridView的自动滚动
			smoothScrollToPositionFromTop(mDragPosition, view.getTop()
					+ scrollY);
		}
	};

	/**
	 * 交换item,并且控制item之间的显示与隐藏效果
	 * 
	 * @param moveX
	 * @param moveY
	 */
	private void onSwapItem(int moveX, int moveY) {
		// 获取我们手指移动到的那个item的position
		int tempPosition = pointToPosition(moveX, moveY);

		// 假如tempPosition 改变了并且tempPosition不等于-1,则进行交换
		if (tempPosition != mDragPosition
				&& tempPosition != AdapterView.INVALID_POSITION) {
			getChildAt(tempPosition - getFirstVisiblePosition()).setVisibility(
					View.INVISIBLE);// 拖动到了新的item,新的item隐藏掉
			getChildAt(mDragPosition - getFirstVisiblePosition())
					.setVisibility(View.VISIBLE);// 之前的item显示出来

			if (onChanageListener != null) {
				onChanageListener.onChange(mDragPosition, tempPosition);
			}

			mDragPosition = tempPosition;
		}
	}

	/**
	 * 停止拖拽我们将之前隐藏的item显示出来，并将镜像移除
	 */
	private void onStopDrag() {
		getChildAt(mDragPosition - getFirstVisiblePosition()).setVisibility(
				View.VISIBLE);
		removeDragImage();
	}

	/**
	 * 获取状态栏的高度
	 * 
	 * @param context
	 * @return
	 */
	private static int getStatusHeight(Context context) {
		int statusHeight = 0;
		Rect localRect = new Rect();
		((Activity) context).getWindow().getDecorView()
				.getWindowVisibleDisplayFrame(localRect);
		statusHeight = localRect.top;
		if (0 == statusHeight) {
			Class<?> localClass;
			try {
				localClass = Class.forName("com.android.internal.R$dimen");
				Object localObject = localClass.newInstance();
				int i5 = Integer.parseInt(localClass
						.getField("status_bar_height").get(localObject)
						.toString());
				statusHeight = context.getResources().getDimensionPixelSize(i5);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return statusHeight;
	}

	/**
	 * 
	 * @author xiaanming
	 * 
	 */
	public interface OnChanageListener {

		/**
		 * 当item交换位置的时候回调的方法，我们只需要在该方法中实现数据的交换即可
		 * 
		 * @param form
		 *            开始的position
		 * @param to
		 *            拖拽到的position
		 */
		public void onChange(int form, int to);
	}

	public boolean isDrag() {
		return isDrag;
	}

	public void setDrag(boolean isDrag) {
		this.isDrag = isDrag;
	}
	
	
}
